use std::time::Duration;

use honeybee::prelude::*;
use honeybee::Result;
use honeybee_proto::{client, hall, room};

use crate::connect::{Connect, SendUserMsg};

pub struct User {
    account: String,
    uid: i64,
    stream: Addr<Connect>,
    peer_addr: String,
}

impl User {
    pub fn new(account: String, uid: i64, stream: Addr<Connect>, peer_addr: String) -> Self {
        Self {
            account,
            uid,
            stream,
            peer_addr,
        }
    }

    fn send<T: 'static + MessageId + prost::Message>(&mut self, msg: T) {
        let _ = self.stream.send(SendUserMsg(msg));
    }
}

#[async_trait::async_trait]
impl Actor for User {
    fn name(&self) -> &str {
        "Robot"
    }

    async fn started(&mut self, ctx: &mut Context<Self>) -> Result<()> {
        ctx.send_interval(HeartBeat, Duration::from_secs(5));

        info!("{} robot login on", self);

        Ok(())
    }

    async fn stopped(&mut self, _ctx: &mut Context<Self>) {
        info!("{} stoped", self);
    }
}

#[message]
pub struct Disconnected;
#[async_trait::async_trait]
impl Handler<Disconnected> for User {
    async fn handle(&mut self, ctx: &mut Context<Self>, _: Disconnected) -> Result<()> {
        ctx.stop(None);
        info!("{} disconnected", self);
        Ok(())
    }
}

impl std::fmt::Display for User {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            f,
            "user account:{} uid:{},{}",
            self.account, self.uid, self.peer_addr
        )
    }
}

#[message]
#[derive(Clone)]
struct HeartBeat;
#[async_trait::async_trait]
impl Handler<HeartBeat> for User {
    async fn handle(&mut self, _ctx: &mut Context<Self>, _: HeartBeat) -> Result<()> {
        self.send(hall::HeartBeat {});
        Ok(())
    }
}

#[async_trait::async_trait]
impl AnyHandler<hall::HeartBeat> for User {
    async fn handle(&mut self, _ctx: &mut Context<Self>, _: hall::HeartBeat) -> Result<()> {
        Ok(())
    }
}

#[async_trait::async_trait]
impl AnyHandler<hall::Person> for User {
    async fn handle(&mut self, _ctx: &mut Context<Self>, _msg: hall::Person) -> Result<()> {
        //debug!("{} receive msg:{:?}", self, msg);
        Ok(())
    }
}

#[async_trait::async_trait]
impl AnyHandler<room::RspCreateRoomState> for User {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        msg: room::RspCreateRoomState,
    ) -> Result<()> {
        debug!("{} receive:{:?}", self, msg);
        Ok(())
    }
}

#[async_trait::async_trait]
impl AnyHandler<client::RspLocalUscAppTest> for User {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        msg: client::RspLocalUscAppTest,
    ) -> Result<()> {
        debug!("{} receive:{:?}", self, msg);
        Ok(())
    }
}

#[async_trait::async_trait]
impl AnyHandler<client::RspKickout> for User {
    async fn handle(&mut self, _ctx: &mut Context<Self>, msg: client::RspKickout) -> Result<()> {
        debug!("{} receive:{:?}", self, msg);
        Ok(())
    }
}
